#!/usr/bin/env python
""" Parameter Parser for command line interface.

AnyProg  arg1 arg2 aoption=10 boption=[1,2,3,4] +doption -coption

+option is same as option=True
-option is same as option=False

if ambiguous the option names can be shortend.

AnyProg  arg1 arg2 a=10 b=[1,2,3,4] +d -c

Configuration with array
optnames=[
        { 'name':'outfile_name'         ,'type':str,  'default':'out.hex','comment':'Name of the output file.' },
        { 'name':'infile_name'          ,'type':str,  'default':'in.hex','comment':'Name of the input file.'},
        { 'name':'address'              ,'type':int,  'default':None,     'comment':'Address.'}]

"""


class argopt:
    optnames=[]
    current_args=[]
    current_opots={}
    
    def __init__(self, option_list):
        self.optnames=option_list
        self.add_default()

    def find_optname( self, text ):
        rv=[]
        text=text.lower()
        for key in self.optnames:
            if key['name'].lower().startswith(text):
                rv.append(key['name'])
        return rv
            

    def merge_cfg_file(self, filename ):
        g={}
        l={}
        exec(open(filename).read(),g,l)
        
        for item in self.optnames:
            if item['name'] in l.keys():
                self.current_opots[item['name']] = l[item['name']]

    def add_default(self):
        for item in self.optnames:
            #if item['default']!=None:
                self.current_opots[item['name']]=item['default']
                
    def parameter(self, argv):
        unknown=[]
        for pos in range(1,len(argv)):
            if argv[pos][0]=='+':
                items=(argv[pos][1:],'True')
            else:
                if argv[pos][0]=='-':
                    items=(argv[pos][1:],'False')
                else:
                    items=argv[pos].split('=')
            if len(items)==1:# is an argument 
                self.current_args.append(items[0])        
            else:
                names=self.find_optname(items[0])
                if len(names)==0:
                    unknown.append( (items[0],()))
                else:
                    if len(names)>1:
                        unknown.append( (items[0],names) )
                    else:
                        #add option to dict
                        try:
                            new_value = eval(items[1])
                        except:
                            new_value =items[1]
                        #if names[0] in self.current_opots: #already set - overwrite
                        #    unknown.append( (items[0],names,new_value) )
                        self.current_opots[names[0]]=new_value
        return unknown,self.current_args,self.current_opots

    def parameter_help(self):
        rv=''
        for item in self.optnames:
            rv+='  - {:20}  {}\n'.format(item['name'],item['comment'])            
        return rv


def print_unknown( unknownlist,prefix="",appendix=""  ):
    for item in unknownlist:
        if len(item[1])==0:
            print( prefix,'Option "'+item[0]+'" is unknown.'+appendix)
        else:
            print( prefix,'Option "'+item[0]+'" is ambiguous.' )
            print( 'Could be one of the following:'+str(item[1]))
            print( appendix)
			
def parse(  option_names, help_text="", min_args=None, max_args=None, argv=None ):
    import sys
    error = False;

    if argv==None:
        argv=sys.argv
    p=argopt(option_names)
    unknown,args,opts = p.parameter( argv )
    if len(unknown)>0:
        error=True
        print_unknown(unknown,"ERROR - ","Option is unknown.")     	

    if min_args!=None:
        if len(args)<min_args:
            print(" ERROR - At least {:d} arguments expected.".format( min_args ) )
            error=True
            
    if max_args!=None:
        if len(args)>max_args:
            print(" ERROR - Not more than {:d} arguments expected.".format( max_args ) )		
            error=True
            
    if opts['help']==True or error==True:
        print (help_text)
        print( '')        
        print( 'Parameters:')
        print( p.parameter_help())

    return error,unknown,args,opts
       
        
        

        
if __name__=="__main__":

    import sys
    
    data= [
        { 'name':'outfile_name'         ,'type':type(str),  'default':'out.hex','comment':'Name of the output file.' },
        { 'name':'infile_name'          ,'type':type(str),  'default':'out.hex','comment':'Name of the input file.'},
        { 'name':'address'              ,'type':type(int),  'default':None,     'comment':'Address of BIS-Address.'},
        { 'name':'segments'             ,'type':type(list), 'default':None,     'comment':'List of segement addresses.'},
        { 'name':'version'              ,'type':type(int),  'default':0x1,      'comment':'Version number of the BIS.'},
        { 'name':'diagnostic_version'   ,'type':type(int),  'default':0x1,      'comment':'Diagnostic version number.'},
        { 'name':'reserved'             ,'type':type(int),  'default':0x0,      'comment':'Value of the reserved field. '},
        { 'name':'help'                 ,'type':type(bool), 'default':False,    'comment':'Print help text. '},
        ]
    
	
    help_text="""Test of argopt module
	Add some function explanation here
	syntax:
			abc.py [args] opts
	exampel:
			abc.py test.c version=1.1"""
    error,unknown,args,opts = parse( data, help_text,1,1 )


    print( str(error ) )
    print( str(unknown ) )
    print( str(args))
    print( str(opts))
        
    